package com.qf.listener;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.qf.config.DelayedConfig;
import com.qf.constant.CacheConstants;
import com.qf.constant.RabbitMQConstants;
import com.qf.feign.CacheFeign;
import com.qf.model.StandardReport;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.Map;

/**
 *
 *  监听 报告队列
 * @author Ypl
 * @version V1.0
 * @Project OctoberAndNovember
 * @Package com.qf.listener
 * @Description:
 * @Date 2022/11/11 10:43
 */
@SuppressWarnings("all")
@Component
@Slf4j
public class PushSmsReportListener {

    @Autowired
    CacheFeign cacheFeign;

    @Autowired
    RestTemplate restTemplate;

    @Autowired
    RabbitTemplate rabbitTemplate;


    /**
     *
     *
     * 监听 报告队列
     *
     *
     */
    @RabbitListener(queues = RabbitMQConstants.TOPIC_PUSH_SMS_REPORT)
    public void pushSmsReportListener(StandardReport report, Channel channel, Message message) throws IOException {
        //获取客户端的ID
        //根据clientId 去redis中获取客户端对象
        Map clientMap = cacheFeign.hMGet(CacheConstants.CACHE_PREFIX_CLIENT + report.getClientID());
        //设置发送的地址
        String receivestatusurl =String.valueOf(clientMap.get("receivestatusurl"));
        report.setReceiveStatusUrl(receivestatusurl);


        //获取客户端的 回报 【 isreturnstatus 】 如果是1 就需要回报，如果不是就消费 状态
        String isreturnstatus =String.valueOf(clientMap.get("isreturnstatus"));
        if("1".equalsIgnoreCase(isreturnstatus)){
            //修改发送次数 要+1
            //发送报告 返回一个值是否在成功
            //发送一次 发送的次数就+1 【第一次发送就+1】
            report.setSendCount(report.getSendCount()+1);

            //发送 报告
            String result = sendReport(report);

            //判断是否发送成功
            if(!isSuccess(result)){
                //如果发送失败 就把消息放到延时队列里面
                pushDelayMsg(report);
            }
            //确认消息消费
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        }else{
            //手动ACK  确认消费
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        }
    }

    /**
     *
     * 发送给客户端短信
     *
     */
    private String sendReport(StandardReport report) {

        try {
            //将对象转换为json对象
            ObjectMapper objectMapper = new ObjectMapper();
            String json = objectMapper.writeValueAsString(report);

            //设置请求体数据类型
            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8);

            //获取http实体类
            HttpEntity httpEntity = new HttpEntity(json,httpHeaders);
            //获取发送的地址 url
            String url = report.getReceiveStatusUrl();
            //发送请求 返回响应实体类
            ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, httpEntity, String.class);

            //如果成功返回数据 判断
            String body = responseEntity.getBody();
            return body;
        } catch (Exception e) {
            //响应失败 返回空
            e.printStackTrace();
            return null;
        }
    }


    /**
     *
     * 判断响应的 body 是否有数据
     *
     */
    private boolean isSuccess(String result) {
        //如果为空 那么就返回false，SUCCESS 通过客户端响应的数据
        if(result == null || !result.equalsIgnoreCase("SUCCESS")){
            return false;
        }
        return true;
    }

    /**
     * 消息发送到 延时队列 中
     */
    Integer[] ttl = new Integer[]{0, 10*1000, 30*1000, 60*1000, 100*1000};

    private void pushDelayMsg(StandardReport report) {
        //判断发送的次数 如果超过了 就不再发送了
        int sendCount = report.getSendCount();
        if(sendCount >= ttl.length){
            return;
        }

        //发送的时间+1
        report.setSendCount(report.getSendCount() + 1);
        //发送到 延时队列
        rabbitTemplate.convertAndSend(DelayedConfig.DELAYED_EXCHANGE,"routinKey",report,(message -> {
            //设置消息在队列中的延时时间
            message.getMessageProperties().setDelay(ttl[report.getSendCount() - 1]);
            return message;
        }));
    }

    /**
     *
     * 监听 延时队列
     *
     */
    @RabbitListener(queues = DelayedConfig.DELAYED_QUEUE)
    public void delayedQueueListener(StandardReport report,Channel channel,Message message){
        log.debug("第{}次发送报告！",report.getSendCount());

        //发送报告
        String result = sendReport(report);

        //如果发送失败就添加到延时队列里里面
        if(!isSuccess(result)){
            this.pushDelayMsg(report);
        }

        // ACK 确认消费
        try {
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
